package com.bsj.travel.device.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsj.travel.cached.redis.RedisCached;
import com.bsj.travel.constant.NumericalConstants;
import com.bsj.travel.constant.RegularExpressionConstants;
import com.bsj.travel.constants.RedisConstant;
import com.bsj.travel.def.common.DO.ProductDO;
import com.bsj.travel.def.common.DO.SubscribeDO;
import com.bsj.travel.def.common.DTO.web.subscribe.SubscribeDTO;
import com.bsj.travel.def.common.DTO.web.subscribe.SubscribeSearchDTO;
import com.bsj.travel.def.common.VO.SubscribeVO;
import com.bsj.travel.def.global.JsonResult;
import com.bsj.travel.def.global.JsonResultEnum;
import com.bsj.travel.device.service.SubscribeService;
import com.bsj.travel.exception.ApiException;
import com.bsj.travel.mapper.mysql.ProductMapper;
import com.bsj.travel.mapper.mysql.SubscribeMapper;
import com.bsj.travel.security.auth.AuthProduct;
import com.bsj.travel.util.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/***
 * @description SubscribeServiceImpl
 * @author LiJiaXin
 * @version 1.0.0
 * @time 2024/2/27 11:36
 **/
@Service
public class SubscribeServiceImpl implements SubscribeService {

    @Resource
    private SubscribeMapper subscribeMapper;

    @Resource
    private ProductMapper productMapper;

    @Autowired
    private AuthProduct authProduct;

    @Autowired
    private RedisCached redisCached;

    /**
     * 添加订阅
     *
     * @param subscribeDTO
     * @return com.bsj.travel.def.global.JsonResult
     * @author ljx
     * @time 2024/2/27 11:54
     */
    @Override
    public JsonResult addSubscribe(SubscribeDTO subscribeDTO) {
        paramCheck(subscribeDTO);
        // 不加密，设置秘钥为空
        if (subscribeDTO.getIsEncrypt() == 1) {
            subscribeDTO.setSecretKey(null);
        }
        SubscribeDO subscribeDO = new SubscribeDO();
        BeanUtils.copyProperties(subscribeDTO, subscribeDO);
        if (subscribeMapper.insert(subscribeDO) > 0) {
            ProductDO productDO = productMapper.selectById(subscribeDO.getProductId());
            redisCached.set(RedisConstant.PRODUCT_SUBSCRIBE_INFO_KEY + productDO.getProductKey(), subscribeDO);
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 秘钥校验
     *
     * @param secretKey
     * @return
     * @author ljx
     * @time 2024/3/26 20:01
     */
    private void keyCheck(String secretKey) {
        Pattern pattern = Pattern.compile(RegularExpressionConstants.CHINESE);
        Matcher matcher = pattern.matcher(secretKey);
        if (matcher.find()) {
            throw new ApiException(JsonResultEnum.SECRET_KEY_CANNOT_CONTAIN_CHINESE);
        }
        int length = secretKey.length();
        if (length != 16 && length != 24 && length != 32) {
            throw new ApiException(JsonResultEnum.SECRET_KEY_FORMAT_ERROR);
        }
    }

    /**
     * 参数校验
     *
     * @param subscribeDTO
     * @return void
     * @author ljx
     * @time 2024/2/29 11:55
     */
    private void paramCheck(SubscribeDTO subscribeDTO) {
        Long productId = subscribeDTO.getProductId();
        if (!productMapper.exists(Wrappers.<ProductDO>lambdaQuery().eq(ProductDO::getProductId, productId))) {
            throw new ApiException(JsonResultEnum.PRODUCT_IS_NOT_EXIST);
        }
        authProduct.permissionCheck(productId);
        if (subscribeDTO.getIsEncrypt().equals(NumericalConstants.TWO)) {
            String secretKey = subscribeDTO.getSecretKey();
            if (StringUtils.isBlank(secretKey)) {
                throw new ApiException(JsonResultEnum.SECRET_KEY_IS_NULL);
            } else {
                keyCheck(secretKey);
            }
        }
        List<Integer> pushType = Arrays.stream(subscribeDTO.getPushType().split(",")).map(Integer::parseInt).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(pushType)) {
            throw new ApiException(JsonResultEnum.PUSH_TYPE_IS_NULL);
        }
        if (!List.of(NumericalConstants.ONE, NumericalConstants.TWO, NumericalConstants.THREE).containsAll(pushType)) {
            throw new ApiException(JsonResultEnum.PUSH_TYPE_IS_NOT_EXIST);
        }
    }

    /**
     * 删除订阅
     *
     * @param id
     * @return com.bsj.travel.def.global.JsonResult
     * @author ljx
     * @time 2024/2/27 11:55
     */
    @Override
    public JsonResult deleteSubscribe(Long id) {
        if (id == null) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        SubscribeDO subscribeDO = subscribeMapper.selectById(id);
        if (subscribeDO == null) {
            return JsonResult.fail(JsonResultEnum.SUBSCRIBE_IS_NOT_EXIST);
        }
        Long productId = subscribeDO.getProductId();
        authProduct.permissionCheck(productId);
        if (subscribeMapper.deleteById(id) > 0) {
            ProductDO productDO = productMapper.selectById(productId);
            redisCached.del(RedisConstant.PRODUCT_SUBSCRIBE_INFO_KEY + productDO.getProductKey());
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 修改订阅
     *
     * @param subscribeDTO
     * @return com.bsj.travel.def.global.JsonResult
     * @author ljx
     * @time 2024/2/27 11:55
     */
    @Override
    public JsonResult updateSubscribe(SubscribeDTO subscribeDTO) {
        paramCheck(subscribeDTO);
        Long id = subscribeDTO.getId();
        if (id == null) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        SubscribeDO oldSubscribeDO = subscribeMapper.selectById(id);
        if (oldSubscribeDO == null) {
            return JsonResult.fail(JsonResultEnum.SUBSCRIBE_IS_NOT_EXIST);
        }
        Long productId = subscribeDTO.getProductId();
        if (!productId.equals(oldSubscribeDO.getProductId())) {
            return JsonResult.fail(JsonResultEnum.CANNOT_CHANGE_THE_BINDING_PRODUCT);
        }
        if (!subscribeDTO.getSubscribeType().equals(oldSubscribeDO.getSubscribeType())) {
            return JsonResult.fail(JsonResultEnum.SUBSCRIBE_TYPE_CANNOT_BE_UPDATE);
        }
        // 不加密，设置秘钥为空
        if (subscribeDTO.getIsEncrypt() == 1) {
            subscribeDTO.setSecretKey(null);
        }
        SubscribeDO subscribeDO = new SubscribeDO();
        BeanUtils.copyProperties(subscribeDTO, subscribeDO);
        if (subscribeMapper.updateById(subscribeDO) > 0) {
            ProductDO productDO = productMapper.selectById(productId);
            redisCached.set(RedisConstant.PRODUCT_SUBSCRIBE_INFO_KEY + productDO.getProductKey(), subscribeDO);
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 根据订阅id获取订阅信息
     *
     * @param id
     * @return com.bsj.travel.def.common.VO.SubscribeVO
     * @author ljx
     * @time 2024/2/27 11:55根据订阅id的取订阅信息
     */
    @Override
    public SubscribeVO getSubscribeInfoById(Long id) {
        if (id == null) {
            throw new ApiException(JsonResultEnum.PARAM_ERROR);
        }
        SubscribeDO subscribeDO = subscribeMapper.selectById(id);
        if (subscribeDO == null) {
            throw new ApiException(JsonResultEnum.SUBSCRIBE_IS_NOT_EXIST);
        }
        SubscribeVO subscribeVO = new SubscribeVO();
        BeanUtils.copyProperties(subscribeDO, subscribeVO);
        return subscribeVO;
    }

    /**
     * 订阅分页
     *
     * @param subscribeSearchDTO
     * @return com.bsj.travel.def.global.JsonResult<java.util.List < com.bsj.travel.def.common.VO.SubscribeVO>>
     * @author ljx
     * @time 2024/2/27 11:56
     */
    @Override
    public JsonResult<List<SubscribeVO>> pageSubscribe(SubscribeSearchDTO subscribeSearchDTO) {
        List<SubscribeVO> subscribeVOS = new LinkedList<>();
        IPage<SubscribeDO> page = new Page<>(subscribeSearchDTO.getPageNumber(), subscribeSearchDTO.getPageSize());
        Long productId = subscribeSearchDTO.getProductId();
        QueryWrapper<SubscribeDO> queryWrapper = new QueryWrapper<>();
        if (productId != null) {
            queryWrapper.eq("productId", productId);
        }
        IPage<SubscribeDO> iPage = subscribeMapper.selectPage(page, queryWrapper);
        int total = (int) iPage.getTotal();
        if (total == NumericalConstants.ZERO) {
            return JsonResult.success(subscribeVOS, total);
        }
        subscribeVOS = iPage.getRecords().stream().map(subscribeDO -> {
            SubscribeVO subscribeVO = new SubscribeVO();
            BeanUtils.copyProperties(subscribeDO, subscribeVO);
            subscribeVO.setCreateTime(DateUtils.parseDateToStr(subscribeDO.getCreateTime()));
            return subscribeVO;
        }).collect(Collectors.toList());
        return JsonResult.success(subscribeVOS, total);
    }
}
